package demoMod.gdxform.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Interpolation;
import demoMod.gdxform.abstracts.Container;
import demoMod.gdxform.core.AbstractAction;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.interfaces.Element;
import demoMod.gdxform.interfaces.KeyboardEventSubscriber;
import demoMod.gdxform.interfaces.MouseEventSubscriber;

public class GMenuList extends Container<GMenuItem> implements MouseEventSubscriber, KeyboardEventSubscriber {
    private float menuItemHeight = 30.0F;
    private GMenuItem parentItem;

    public GMenuList() {
        actionManager.addToSequenceBot(getMenuAppearAnimation());
    }

    protected AbstractAction getMenuAppearAnimation() {
        final float d = 0.3F;
        return new AbstractAction.Builder().setDuration(d).setActionBody(duration -> {
            int index = 0;
            float relativeY = getHeight() * 2.0F - menuItemHeight;
            for (GMenuItem gMenuItem : getElements()) {
                gMenuItem.setY(relativeY - (float) index * menuItemHeight - Interpolation.exp10Out.apply((d - duration) / d) * getHeight());
                index++;
            }
            return duration < 0;
        }).build();
    }

    @Override
    public void update() {
        int index = 0;
        float relativeY = getHeight() - menuItemHeight;
        for (GMenuItem gMenuItem : getElements()) {
            gMenuItem.setY(relativeY - (float) index * menuItemHeight);
            index++;
        }
        super.update();
    }

    @Override
    public void addElement(GMenuItem element) {
        element.setPriority(getElements().size());
        element.setHeight(this.menuItemHeight);
        super.addElement(element);
    }

    @Override
    public void removeElement(Element element) {
        super.removeElement(element);
        int index = 0;
        for (GMenuItem gMenuItem : getElements()) {
            gMenuItem.setPriority(index);
            index++;
        }
    }

    public float getMenuItemHeight() {
        return menuItemHeight;
    }

    public void setMenuItemHeight(float menuItemHeight) {
        if (menuItemHeight != this.menuItemHeight) {
            this.menuItemHeight = menuItemHeight;
            for (GMenuItem gMenuItem : getElements()) {
                gMenuItem.setHeight(this.menuItemHeight);
                gMenuItem.setIconWidth(this.menuItemHeight);
            }
        }
    }

    public GMenuItem getParentItem() {
        return parentItem;
    }

    void setParentItem(GMenuItem parentItem) {
        this.parentItem = parentItem;
    }

    @Override
    public float getX(boolean isAbsolute) {
        if (this.parentItem != null) {
            if (this.parentItem.getParent() instanceof GMenuBar) {
                return this.parentItem.getX(isAbsolute);
            } else {
                return this.parentItem.getX(isAbsolute) + this.parentItem.getWidth();
            }
        }
        return super.getX(isAbsolute);
    }

    @Override
    public float getY(boolean isAbsolute) {
        if (this.parentItem != null) {
            float y = this.parentItem.getParent() instanceof GMenuBar ? this.parentItem.getY(isAbsolute) - this.getHeight() : this.parentItem.getY(isAbsolute);
            if (isAbsolute && y < 0) {
                y = 0;
            }
            return y;
        }
        return super.getY(isAbsolute);
    }

    @Override
    public float getHeight() {
        return menuItemHeight * (float) getElements().size();
    }

    @Override
    public boolean keyDown(int keyCode) {
        for (GMenuItem item : getElements()) {
            item.setSelected(item.keyDown(keyCode));
            if (item.isSelected()) {
                for (GMenuItem item1 : getElements()) {
                    if (item1 != item) {
                        item1.setSelected(false);
                    }
                }
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean keyUp(int keyCode) {
        return false;
    }

    @Override
    public boolean keyTyped(char key) {
        return false;
    }

    @Override
    public boolean clickDown(int screenX, int screenY, int button) {
        for (GMenuItem item : getElements()) {
            if (item.clickDown(screenX, screenY, button)) {
                return true; //如果有菜单项响应这个事件，则由此菜单项决定是否销毁此菜单列表
            }
        }
        //如果没有菜单项响应这个事件，则销毁此菜单列表
        if (this.parentItem == null || this.parentItem.getParent() instanceof GMenuBar) disappear();
        if (this.parentItem != null && this.parentItem.getParent() instanceof GMenuBar) {
            this.parentItem.setSelected(false);
        }
        return false;
    }

    @Override
    public boolean clickUp(int screenX, int screenY, int button) {
        for (GMenuItem item : getElements()) {
            if (item.clickUp(screenX, screenY, button)) {
                return true;
            }
        }
        return false;
    }

    protected void disappear() {
        actionManager.addToSequenceBot(new AbstractAction.Builder().setActionBody(duration -> {
            if (getParent() != null) {
                getParent().removeElement(this);
            } else {
                FormManager.getInstance().removeContainer(this);
            }
            actionManager.addToSequenceBot(new AbstractAction.Builder().setActionBody(duration1 -> {
                if (getParent() != null) this.dispose();
                return true;
            }).build());
            return true;
        }).build());
        for (GMenuItem item : getElements()) {
            if (item.getSubMenuInstance() != null) {
                item.getSubMenuInstance().disappear();
            }
        }
    }

    @Override
    public boolean mouseDragged(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        boolean hovered = screenX >= getX(true) && screenX <= getX(true) + getWidth() &&
                Gdx.graphics.getHeight() - screenY >= getY(true) && Gdx.graphics.getHeight() - screenY <= getY(true) + getHeight() && enabled();
        if (hovered) {
            for (GMenuItem item : getElements()) {
                item.mouseMoved(screenX, screenY);
            }
        }
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }

    @Override
    public boolean moveToElementBorder(Element element) {
        return false;
    }
}
